﻿/*
 * Copyright (c) 2010 Piotr Polesiuk
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

using System;
using System.Collections.Generic;
using System.Drawing;

namespace Fotometr
{
    static class Core
    {
        public enum Tool
        {
            Null, Zoom, Foto1, Foto3
        }

        public struct Foto1Result
        {
            public float R;
            public float G;
            public float B;
            public float Total;

            public Foto1Result(float r, float g, float b, float total)
            {
                R = r;
                G = g;
                B = b;
                Total = total;
            }

            public static Foto1Result operator + (Foto1Result fr, Color col)
            {
                return new Foto1Result(fr.R + col.R, fr.G + col.G, fr.B + col.B, fr.Total + col.R + col.G + col.B);
            }

            public static Foto1Result operator / (Foto1Result fr, float x)
            {
                return new Foto1Result(fr.R/x, fr.G/x, fr.B/x, fr.Total/x);
            }

            public static Foto1Result operator / (Foto1Result fr1, Foto1Result fr2)
            {
                return new Foto1Result(fr1.R / fr2.R, fr1.G / fr2.G, fr1.B / fr2.B, fr1.Total / fr2.Total);
            }

            public static Foto1Result operator - (Foto1Result fr1, Foto1Result fr2)
            {
                return new Foto1Result(fr1.R - fr2.R, fr1.G - fr2.G, fr1.B - fr2.B, fr1.Total - fr2.Total);
            }

            public override string ToString()
            {
 	             return R.ToString() + " " + G.ToString() + " " + B.ToString() + " " + Total.ToString();
            }
        }

        public struct Foto3Result
        {
            public Foto1Result Data;
            public Foto1Result Background;

            public Foto3Result(Foto1Result data, Foto1Result background)
            {
                Data = data - background;
                Background = background;
            }
        }

        public static Bitmap Bitmap;
        public static float Scale = 1.0f;

        public static Tool SelectedTool = Tool.Null;

        public static float Foto1Radius = 10.0f;

        public static float Foto3Radius1 = 8.0f;
        public static float Foto3Radius2 = 14.0f;
        public static float Foto3Radius3 = 21.0f;

        public static float CursorPositionX;
        public static float CursorPositionY;

        public static bool ShowMagnitudo = false;

        public static List<Foto1Result> ResultList = new List<Foto1Result>();

        public static Foto1Result Fotometry1()
        {
            int size = (int)Foto1Radius + 1;
            float rsq = Foto1Radius * Foto1Radius;
            int cx = (int)(CursorPositionX / Scale);
            int cy = (int)(CursorPositionY / Scale);
            int sx = cx - size;
            int sy = cy - size;
            int ex = cx + size + 1;
            int ey = cy + size + 1;
            if (sx < 0)
                sx = 0;
            if (sy < 0)
                sy = 0;
            if (ex > Bitmap.Width)
                ex = Bitmap.Width;
            if (ey > Bitmap.Height)
                ey = Bitmap.Height;

            int pixelCnt = 0;
            Foto1Result signalCnt = new Foto1Result(0.0f, 0.0f, 0.0f, 0.0f);

            for (int y = sy; y != ey; y++)
                for (int x = sx; x != ex; x++)
                {
                    if ((x-cx)*(x-cx) + (y-cy)*(y-cy) <= rsq)
                    {
                        signalCnt += Bitmap.GetPixel(x, y);
                        pixelCnt++;
                    }
                }

            return signalCnt / (float)pixelCnt;
        }

        public static Foto3Result Fotometry3()
        {
            int size = (int)Foto3Radius3 + 1;
            float rsq1 = Foto3Radius1 * Foto3Radius1;
            float rsq2 = Foto3Radius2 * Foto3Radius2;
            float rsq3 = Foto3Radius3 * Foto3Radius3;
            int cx = (int)(CursorPositionX / Scale);
            int cy = (int)(CursorPositionY / Scale);
            int sx = cx - size;
            int sy = cy - size;
            int ex = cx + size + 1;
            int ey = cy + size + 1;
            if (sx < 0)
                sx = 0;
            if (sy < 0)
                sy = 0;
            if (ex > Bitmap.Width)
                ex = Bitmap.Width;
            if (ey > Bitmap.Height)
                ey = Bitmap.Height;

            int spixelCnt = 0;
            int bpixelCnt = 0;
            Foto1Result signalCnt = new Foto1Result(0.0f, 0.0f, 0.0f, 0.0f);
            Foto1Result backCnt = new Foto1Result(0.0f, 0.0f, 0.0f, 0.0f);

            for (int y = sy; y != ey; y++)
                for (int x = sx; x != ex; x++)
                {
                    int rsq = (x - cx) * (x - cx) + (y - cy) * (y - cy);
                    if (rsq <= rsq1)
                    {
                        signalCnt += Bitmap.GetPixel(x, y);
                        spixelCnt++;
                    }
                    else if (rsq >= rsq2 && rsq <= rsq3)
                    {
                        backCnt += Bitmap.GetPixel(x, y);
                        bpixelCnt++;
                    }
                }

            if (bpixelCnt == 0)
                bpixelCnt = 1;
            return new Foto3Result(signalCnt / (float)spixelCnt, backCnt / (float)bpixelCnt);
        }

        public static string FormatValue(string name, float value)
        {
            string ret = name + " = " + value;
            if (ShowMagnitudo && value > 0.0f)
                return ret + "\t(" + (-2.5f * Math.Log10(value) + 7.0f).ToString("0.00") + "m)\n";
            else
                return ret + "\n";
        }
    }
}
